package com.budwk.app.sqfw.services.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.RandomUtil;
import com.budwk.app.exception.Asserts;
import com.budwk.app.exception.ServiceException;
import com.budwk.app.sms.dto.SmsMsgDTO;
import com.budwk.app.sms.service.OpaSmsService;
import com.budwk.app.sms.service.TencentSmsService;
import com.budwk.app.sqfw.constants.SqfwVerifyCodeTypeConstants;
import com.budwk.app.sqfw.models.Sqfw_verifyCode;
import com.budwk.app.sqfw.services.SqfwVerifyCodeService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.util.IpUtils;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

import java.util.Date;
import java.util.List;

/**
 * @author ZY.Wang
 * @since 2023/7/10
 */
@IocBean(args = {"refer:dao"})
public class SqfwVerifyCodeServiceImpl extends BaseServiceImpl<Sqfw_verifyCode> implements SqfwVerifyCodeService {
    public SqfwVerifyCodeServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private OpaSmsService opaSmsService;

    @Inject
    private SysUserService sysUserService;

    @Inject
    private TencentSmsService tencentSmsService;

    @Override
    public int commonSendCode(String phoneNo, String businessType) {
        String code = RandomUtil.randomNumbers(6);
        int expireMinute = 10;

        String smsSmgContent = "";
        boolean registerCheckFlag = true;

        if (businessType.equals(SqfwVerifyCodeTypeConstants.login_verify_code)) {
            String templateStr = "登陆验证码{}，仅可用于有效性验证，{}分钟内有效。";
            smsSmgContent = StrFormatter.format(templateStr, code, expireMinute);
        }

        if (businessType.equals(SqfwVerifyCodeTypeConstants.rest_password)) {
            String templateStr = "登陆验证码{}，仅可用于有效性验证，{}分钟内有效。";
            smsSmgContent = StrFormatter.format(templateStr, code, expireMinute);
        }

        if (businessType.equals(SqfwVerifyCodeTypeConstants.verify_peer_person)) {
            String templateStr = "同行人验证码{}，仅可用于有效性验证，{}分钟内有效。";
            smsSmgContent = StrFormatter.format(templateStr, code, expireMinute);
            registerCheckFlag = false;
        }
        if (businessType.equals(SqfwVerifyCodeTypeConstants.register_admin_verify_code)) {
            String templateStr = "新用户注册验证码{}，仅可用于有效性验证，{}分钟内有效。";
            smsSmgContent = StrFormatter.format(templateStr, code, expireMinute);
            registerCheckFlag = false;
        }

        if (StringUtils.isNotBlank(smsSmgContent)) {
            return sendCode(phoneNo, businessType, smsSmgContent, code, expireMinute, registerCheckFlag);
        }

        return 0;
    }

    @Override
    public Sqfw_verifyCode checkCode(String phoneNo, String verifyCode, String businessType) {

        if (StringUtils.isBlank(phoneNo)) return null;
        if (StringUtils.isBlank(verifyCode)) return null;

        Cnd cnd = Cnd.NEW();
        cnd.where().and("phone_no", "=", phoneNo).and("business_type", "=", businessType);
        cnd.orderBy("create_date", "desc");
        Sqfw_verifyCode latestVerifyCode = fetch(cnd);

        // 没有相应的code
        if (latestVerifyCode == null) return null;

        // 该code已经使用过了
        if (latestVerifyCode.getUsedFlag()) return null;

        // 验证码已经过期
        if (latestVerifyCode.getExpireTime().compareTo(new Date()) < 0) return null;

        // 验证码不一致
        if (!latestVerifyCode.getCode().equals(verifyCode)) return null;

        return latestVerifyCode;
    }


    private int sendCode(String phoneNo, String businessType, String msgContentStr, String code, Integer expireMinute, Boolean registerCheckFlag) {
        if (registerCheckFlag) {
            // 首先需要验证该手机号是否已经可以进行注册登陆
            try {
                // 因为这个方法会抛出异常，所以只需要拦截异常就ok
                sysUserService.getUserByLoginname(phoneNo);
            } catch (Exception ignored) {
                throw new ServiceException("账号尚未获得授权,请联系街道管理员获得授权");
            }
        }

        // 首先查看该手机号该业务类型是否在一分钟之内发送过验证码 如果发送过进行提示
        boolean passFlag = checkSendPass(phoneNo, businessType);
        if (!passFlag) return -1;

        // 发送短信
        //SmsMsgDTO smsMsgDTO = new SmsMsgDTO();
        //smsMsgDTO.setPhoneNumberSet(Sets.newHashSet(phoneNo));
        //smsMsgDTO.setTemplateParamList(Lists.newArrayList(msgContentStr));
        //Integer messageSendCount = opaSmsService.opaSmsSendOneMessage(smsMsgDTO);

        SmsMsgDTO smsMsgDTO = new SmsMsgDTO();
        smsMsgDTO.setPhoneNumberSet(Sets.newHashSet(phoneNo));
        smsMsgDTO.setTempId("2141853");
        smsMsgDTO.setTemplateParamList(Lists.newArrayList(code + "", expireMinute + ""));
        Integer messageSendCount = tencentSmsService.txSmsSendOneMessage(smsMsgDTO);

        // 添加发送记录
        Sqfw_verifyCode newVerifyCode = new Sqfw_verifyCode();
        newVerifyCode.setCode(code);
        newVerifyCode.setPhoneNo(phoneNo);
        newVerifyCode.setUsedFlag(false);
        newVerifyCode.setCreateDate(new Date());
        newVerifyCode.setIpAddress(IpUtils.getIpAddr());
        newVerifyCode.setBusinessType(businessType);
        newVerifyCode.setSendChannel("opa");
        newVerifyCode.setSendSuccessFlag(messageSendCount > 0);
        newVerifyCode.setExpireTime(DateUtil.offsetMinute(new Date(), expireMinute));
        Sqfw_verifyCode insert = insert(newVerifyCode);
        if (insert != null) return 1;
        return 0;
    }

    private Boolean checkSendPass(String phoneNo, String businessType) {
        Cnd cnd = Cnd.NEW();
        cnd.and("phone_no", "=", phoneNo).and("business_type", "=", businessType).orderBy("create_date", "desc");
        Sqfw_verifyCode verifyCode = fetch(cnd);
        if (verifyCode != null) {
            // 如果上次发送在1分钟之内，不允许进行发送
            Date createDate = verifyCode.getCreateDate();
            return DateUtil.between(createDate, new Date(), DateUnit.MINUTE) >= 1;
        }
        return true;
    }
}
